// Ninf-G-XX, ver. 0.1
// Copyright 2011 National Institute of Advanced Industrial Science and Technology
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cstdio>
#include <assert.h>
#include "ArgShape.hpp"
#include "Exception.hpp"

using namespace ninf::lib;

/*
 * iArgs: interger interpreted parameters
 * len:   length of iArgs
 */
ArgShape :: ArgShape(ParamDesc * desc, int * iArgs, int len)
  : nDim(desc->nDim)
{
  dim = new ArgDim *[nDim];
  for (int i = 0; i < nDim; i++)
    dim[i] = desc->dim[i]->calc(iArgs, len);
}

ArgShape :: ArgShape(const std::vector<int> & config):
  nDim(config.size()){
  dim = new ArgDim *[nDim];
  for (int i = 0; i < nDim; i++)
    dim[i] = new ArgDim(config[i]);
}

ArgShape :: ArgShape(DataInputStream & dis){
  EBEGIN { nDim = dis.readInt();        } EEND
  dim = new ArgDim *[nDim];
  for (int i = 0; i < nDim; i++) {
    int size, start, end, step;
    EBEGIN { size  = dis.readInt(); } EEND
    EBEGIN { start = dis.readInt(); } EEND
    EBEGIN { end   = dis.readInt(); } EEND
    EBEGIN { step  = dis.readInt(); } EEND
    dim[i] = new ArgDim(size, start, end, step);
  }
}

ArgShape :: ~ArgShape()
{
  for (int i = 0; i < nDim; i++){
    if (dim[i] != NULL)
      delete dim[i];
 }
  delete [] dim ;
}

void
ArgShape :: writeOut(DataOutputStream & dos){
  dos.writeInt(nDim);
  for (int i = 0; i < nDim; i++){
    dos.writeInt(dim[i]->size);
    dos.writeInt(dim[i]->start);
    dos.writeInt(dim[i]->end);
    dos.writeInt(dim[i]->step);
  }
}

bool
ArgShape :: compareWith(ArgShape & tmpShape){
  if (this->nDim != tmpShape.nDim)
    return false;
  for (int i = 0; i < nDim; i++){
    if (dim[i]->size  != tmpShape.dim[i]->size)  return false;
    if (dim[i]->start != tmpShape.dim[i]->start) return false;
    if (dim[i]->end   != tmpShape.dim[i]->end)   return false;
    if (dim[i]->step  != tmpShape.dim[i]->step)  return false;
  }
  return true;
}

int
ArgShape :: calcSize(bool shrink){
  if (!shrink){
    int tmp = 1;
    for (int i = 0; i < nDim; i++)
      tmp *= dim[i]->size;
    return tmp;
  } else {
    int tmp = 1;
    for (int i = 0; i < nDim; i++)
      tmp *= dim[i]->countSize();
    return tmp;
  }
}
